#include "manejoDeBloques.h"

void cargarBloque(FILE *archivo,unsigned char* entrada,int size){
        fread(entrada,1,size,archivo);
}

void comprimirUnBloque(FILE* archivoAComprimir,buffer* buffer,int tamanho){
   	unsigned char*	salidaBS;
   	short int indice=0;
  	int* probabilidades;
    int* salidaMTF;

    unsigned char* entrada= malloc(tamanho*sizeof(unsigned char));
    cargarBloque(archivoAComprimir,entrada,tamanho);
    codificarBlockSorting(entrada,&salidaBS,&indice,tamanho);
    fwrite(&indice,1,2,buffer->archivo);

    probabilidades = crearEstadisticaModeloEstructurado();
    salidaMTF = moveToFront(salidaBS,tamanho);

    prepararBufferParaComprimir(buffer,tamanioBloque*50);

    comprimir(salidaMTF+1,*salidaMTF,probabilidades,buffer);
    volcarBloqueComprimidoADisco(buffer);
    vaciarBuffer_(buffer);

    free(probabilidades);
    free(salidaMTF);
    free(salidaBS);
    free(entrada);
}


int comprimirPorBloques(char* nombreDelArchivoAComprimir,char* nombreArchivoAComprimir){
    FILE *archivoAComprimir;
    int error = 0;

    if((archivoAComprimir=fopen(nombreDelArchivoAComprimir,"rb")) == NULL){
        printf("error al abrir el archivo a comprimir");
        error = 1;
	}else{
		fseek(archivoAComprimir,0,SEEK_END);
		int tamanio_real = ftell(archivoAComprimir);
		fseek(archivoAComprimir,0,SEEK_SET);

		int numeroBloques = tamanio_real/tamanioBloque;
		int tamanioUltimoBloque= tamanio_real%tamanioBloque;

		buffer* buffer 	= crearBuffer(nombreArchivoAComprimir,"wb");
		int i;
		double* valoresAnteriores = malloc(sizeof(double)*2);
		memset(valoresAnteriores,0,2*sizeof(double));

		if (numeroBloques > 0){//bloques de archivo
			for(i=0;i<numeroBloques;i++){
				presentarInformacionEnPantalla(valoresAnteriores,i,numeroBloques,"comprimido");
				comprimirUnBloque(archivoAComprimir,buffer,tamanioBloque);
			}
		}
		if(tamanioUltimoBloque > 0)
			comprimirUnBloque(archivoAComprimir,buffer,tamanioUltimoBloque);

		free(valoresAnteriores);
		eliminarBuffer(buffer);
		fclose(archivoAComprimir);
	}
    return error;
}

int descomprimirPorBloques(char* nombreDelArchivoADescomprimir,char* nombreArchivoDescomprimido){
    int* salidaDelDescompresor;
   	int	tamanioSalidaDMTF;
   	int error;
  	unsigned char*	salidaDMTF;
	unsigned char*	salidaDBS;
    int *probabilidades;
    short int indiceBS;
    buffer* buffer;
    int tamanioDeArchivo;
    error = 0;
    buffer 	= crearBuffer(nombreDelArchivoADescomprimir,"rb");
    if (obtenerDescriptorDeArchivo(buffer) == NULL){
    	printf("Error al abrir el archivo a descomprimir\n");
    	error = 1;
    }else{
    	FILE* archivoDescomprimido = fopen(nombreArchivoDescomprimido,"wb");
    	tamanioDeArchivo = tamanioDelArchivo(buffer);
    	double* valoresAnteriores = malloc(sizeof(double)*2);
    	memset(valoresAnteriores,0,2*sizeof(double));

		while(!finDeArchivo(buffer)){
			presentarInformacionEnPantalla(valoresAnteriores,ftell(obtenerDescriptorDeArchivo(buffer)),tamanioDeArchivo,"descomprimido");
			fread(&indiceBS,1,2,buffer->archivo);
			cargarDatosParaDescomprimir(buffer);

			probabilidades = crearEstadisticaModeloEstructurado();
			salidaDelDescompresor = descomprimir(probabilidades,buffer);//
			vaciarBuffer_(buffer);

			salidaDMTF  = deshacerMoveToFront(salidaDelDescompresor+1,*salidaDelDescompresor,&tamanioSalidaDMTF);
			salidaDBS	= decodificarBlockSorting(salidaDMTF,indiceBS,tamanioSalidaDMTF);

			fwrite(salidaDBS,1,tamanioSalidaDMTF,archivoDescomprimido);

			free(salidaDelDescompresor);
			free (probabilidades);
			free(salidaDMTF);
			free(salidaDBS);
		}
		free(valoresAnteriores);
		fclose(archivoDescomprimido);
    }
    eliminarBuffer(buffer);
    return error;
}

void presentarInformacionEnPantalla(double* valoresAnteriores,int i,int numeroBloques,char* comentario){

	double porcentajeActual	  = (double)i / numeroBloques;

	double tiempoAnterior	  = *valoresAnteriores;
	double porcentajeAnterior = *(valoresAnteriores+1);

	double tiempoAproximado;
	printf("\n\t%2.2f %% %s ",porcentajeActual*100,comentario);

	if ( porcentajeAnterior == 0 || tiempoAnterior == 0 ){
		long int tiempoInicio = clock() / (double)CLOCKS_PER_SEC;
		tiempoAproximado	  = tiempoInicio/porcentajeActual-tiempoInicio;
		tiempoAnterior		  = tiempoAproximado;
		porcentajeAnterior	  = porcentajeActual;
	}else{
		tiempoAproximado   	  = tiempoAnterior * (1-porcentajeActual)/(1-porcentajeAnterior);
	}

	if ( tiempoAproximado < (int)tiempoAnterior ){
		tiempoAnterior		  = tiempoAproximado;
		porcentajeAnterior	  = porcentajeActual;

		if (tiempoAproximado <= 60)
			printf("restan %2.0f segundos",tiempoAproximado);
		else{
			int aux = tiempoAproximado/60;
			printf("restan %2i minutos %2i segundos ",aux,(int)tiempoAproximado - aux*60 );
		}
	}
	*valoresAnteriores		  = tiempoAnterior;
	*(valoresAnteriores+1)	  = porcentajeAnterior;
}


